package edu.usc.csci578.model;

import java.util.*;

public class Cluster {
	public static final boolean TYPE_SPEC = true;
	public static final boolean TYPE_INDEP = false;

	public static final String XML_TAG_SPEC = "spec";
	public static final String XML_TAG_INDEP = "indep";

	private String name;
	private boolean type;
	private List<Cluster> lowerClusters = null;
	private List<SClass> classes = null;
	private List<ClusterEdge> edgesIn = null;
	private List<ClusterEdge> edgesOut = null;
	private Map<STopic, Double> topics = null;

	public Cluster(String name) {
		init(name, TYPE_SPEC, true);
	}

	public Cluster(String name, boolean type, boolean isLeaf) {
		init(name, type, isLeaf);
	}

	private void init(String name, boolean type, boolean isLeaf) {
		this.name = name;
		this.type = type;
		edgesIn = new ArrayList<ClusterEdge>();
		edgesOut = new ArrayList<ClusterEdge>();
		topics = new HashMap<STopic, Double>();
		if (isLeaf) {
			classes = new ArrayList<SClass>();
		}
		if (!isLeaf) {
			lowerClusters = new LinkedList<Cluster>();
		}
	}

	public void setType(boolean type) {
		this.type = type;
	}

	public boolean isLeaf() {
		return (lowerClusters.size() == 0);
	}

	public String getName() {
		return name;
	}

	public double getProbablity(STopic t) {
		return topics.containsKey(t) ? topics.get(t) : 0.0;
	}

	public boolean isSpec() {
		return type;
	}

	public boolean isIndep() {
		return !type;
	}

	public boolean contains(Cluster cluster) {
		return lowerClusters.contains(cluster);
	}

	public boolean contains(SClass aClass) {
		return classes.contains(aClass);
	}

	public boolean contains(ClusterEdge edge) {
		return (edgesIn.contains(edge) || edgesOut.contains(edge));
	}

	public boolean contains(ClusterEdge edge, boolean InOrOut) {
		if (InOrOut == ClusterEdge.EDGE_IN_CLUSTER)
			return edgesIn.contains(edge);
		else
			return edgesOut.contains(edge);
	}

	public boolean contains(STopic topic) {
		return topics.containsKey(topic);
	}

	public List<Cluster> getLowerClusters() {
		return lowerClusters;
	}

	public List<SClass> getClasses() {
		return classes;
	}

	public List<ClusterEdge> getEdgesIn() {
		return edgesIn;
	}

	public List<ClusterEdge> getEdgesOut() {
		return edgesOut;
	}

	public List<ClusterEdge> getEdgesAll() {
		List<ClusterEdge> ret = new LinkedList<ClusterEdge>(edgesIn);
		ret.addAll(edgesOut);
		return ret;
	}

	public List<STopic> getTopics() {
		return new LinkedList<STopic>(topics.keySet());
	}

	public double getTopicProbability(STopic topic) {
		return topics.get(topic);
	}

	public boolean add(SClass aClass) {
		if (!contains(aClass) && aClass != null) {
			classes.add(aClass);
			return true;
		}
		return false;
	}

	public boolean add(ClusterEdge edge, boolean InOrOut) {
		if (!contains(edge, InOrOut) && edge != null) {
			if (InOrOut == ClusterEdge.EDGE_IN_CLUSTER) {
				edgesIn.add(edge);
			} else {
				edgesOut.add(edge);
			}
			return true;
		}
		return false;
	}

	/*
	 * public boolean add(DocTopic docTopic) { if (!contains(docTopic) &&
	 * docTopic != null) { docTopics.add(docTopic); return true; } return false;
	 * }
	 */

	public boolean add(STopic topic, double probablity) {
		if (!contains(topic) && topic != null) {
			topics.put(topic, probablity);
			return true;
		}
		return false;
	}

	public boolean add(Cluster cluster) {
		if (cluster != null && !contains(cluster)) {
			lowerClusters.add(cluster);
			return true;
		}
		return false;
	}

	public boolean containsIn(Cluster c) {
		for (ClusterEdge ce : edgesIn) {
			if (ce.contains(c)) {
				return true;
			}
		}
		return false;
	}

	public boolean containsOut(Cluster c) {
		for (ClusterEdge ce : edgesOut) {
			if (ce.contains(c)) {
				return true;
			}
		}
		return false;
	}

	public String toString() {
		String output = "";
		output += "Cluster: " + name + "\n";
		return output;
	}

	public String printIn() {
		StringBuffer sb = new StringBuffer();
		sb.append("EdgeIn: " + edgesIn.size() + "\n");
		for (ClusterEdge ce : edgesIn) {
			sb.append(ce.getSrc().getName() + "\n");
		}
		sb.append("End EdgeIn\n");
		return sb.toString();
	}

	public String printOut() {
		StringBuffer sb = new StringBuffer();
		sb.append("EdgeOut: " + edgesOut.size() + "\n");
		for (ClusterEdge ce : edgesOut) {
			sb.append(ce.getTgt().getName() + "\n");
		}
		sb.append("End EdgeOut\n");
		return sb.toString();
	}
}
